<?php

/**
 * @todo change destroy() to __destruct()
 *
 */

class xnode
{

	/**
	 * @var DOMDocument
	 */
	protected $dom;

	/**
	 * @var DOMNode
	 */
	protected $dom_node;

	public function __construct(DOMNode $dom_node, DOMDocument $dom)
	{
		$this->dom_node = $dom_node;
		$this->dom = $dom;
	}

	public function get_dom()
	{
		return $this->dom;
	}

	public function get_dom_node()
	{
		return $this->dom_node;
	}

	/**
	 * @return xdom
	 */
	public function get_xdom()
	{
		return xdom::create_from_dom($this->dom);
	}

	/**
	 * Enter description here...
	 *
	 * @param unknown_type $node_name
	 * @param unknown_type $text
	 * @return xnode
	 */
	public function create_child_node($node_name, $text = "")
	{
		$new_node = $this->dom->createElement($node_name, htmlspecialchars($text));
		$this->dom_node->appendChild($new_node);
		$new_xnode = new xnode($new_node, $this->dom);
		return $new_xnode;
	}

	/**
	 * Enter description here...
	 *
	 * @param unknown_type $node_name
	 * @param unknown_type $text
	 * @return xnode
	 */
	public function insert_before($node_name, $text = "", xnode $ref_node = null)
	{
		$new_node = $this->dom->createElement($node_name, htmlspecialchars($text));
		$this->dom_node->insertBefore($new_node, $ref_node->get_dom_node());
		$new_xnode = new xnode($new_node, $this->dom);
		return $new_xnode;
	}

	/**
	 * Enter description here...
	 *
	 * @param unknown_type $attr_name
	 * @param unknown_type $attr_value
	 * @return xnode
	 */
	public function set_attr($attr_name, $attr_value = "")
	{
		$this->dom_node->setAttribute($attr_name, $attr_value);
		return $this;
	}

	public function get_attr($attr_name)
	{
		return $this->dom_node->getAttribute($attr_name);
	}

	/**
	 * Enter description here...
	 *
	 * @param unknown_type $text
	 * @param unknown_type $append
	 * @return xnode
	 */
	public function set_text($text, $append = false)
	{
		$text_node = $this->dom->createTextNode($text);
		if ($append || strval($this->get_text()) === "")
		{
			$this->dom_node->appendChild($text_node);
		
		}
		else
		{
			$child_nodes = $this->dom_node->childNodes;
			
			foreach ($child_nodes as $child_node)
			{
				if (get_class($child_node) == "DOMText")
				{
					$this->dom_node->removeChild($child_node);
				}
			}
			$this->dom_node->replaceChild($text_node, $this->dom_node->firstChild);
		}
		return $this;
	}

	public function get_text()
	{
		return $this->dom_node->nodeValue;
	}

	/**
	 * Enter description here...
	 *
	 * @param string $xpath_expression
	 * @param bool $select_only_one
	 * @return array
	 */
	public function xpath($xpath_expression, $select_only_one = false)
	{
		$xpath = new DOMXPath($this->dom);
		$found_nodes = $xpath->query($xpath_expression, $this->dom_node);
		$xnodes = array();
		if ($select_only_one)
		{
			if ($found_nodes->item(0))
			{
				$xnodes[] = new xnode($found_nodes->item(0), $this->dom);
			}
		}
		else
		{
			foreach ($found_nodes as $found_node)
			{
				$xnodes[] = new xnode($found_node, $this->dom);
			}
		}
		return $xnodes;
	}

	/**
	 * Enter description here...
	 *
	 * @param string $xpath_expression
	 * @return xnode
	 */
	public function xpath_one($xpath_expression)
	{
		$xnode_array = $this->xpath($xpath_expression, true);
		if (isset($xnode_array[0]))
		{
			return $xnode_array[0];
		}
		else
		{
			return null;
		}
	}

	/**
	 * Enter description here...
	 *
	 * @param DOMDocument $dom
	 * @param unknown_type $without_root_node
	 * @param unknown_type $deep
	 * @return xnode
	 */
	public function import_dom(DOMDocument $dom, $without_root_node = false, $deep = true)
	{
		$external_root_node = $dom->documentElement;
		
		return $this->import_node($external_root_node, $without_root_node, $deep);
	}

	/**
	 * Enter description here...
	 *
	 * @param xdom $xdom
	 * @param unknown_type $without_root
	 * @param unknown_type $deep
	 * @return xnode
	 */
	public function import_xdom(xdom $xdom, $without_root = false, $deep = true)
	{
		$this->import_dom($xdom->get_dom(), $without_root, $deep);
		return $this;
	}

	public function import_node(DOMNode $external_node, $without_root_node = false, $deep = true)
	{
		if ($without_root_node)
		{
			$external_nodes = $external_node->childNodes;
			foreach ($external_nodes as $external_node)
			{
				$new_node = $this->dom->importNode($external_node, $deep);
				$this->dom_node->appendChild($new_node);
			}
		}
		else
		{
			$new_node = $this->dom->importNode($external_node, $deep);
			$this->dom_node->appendChild($new_node);
		}
		return $this;
	}

	public function import_xnode(xnode $xnode, $without_root = false, $deep = true)
	{
		$this->import_node($xnode->dom_node, $without_root, $deep);
		return $this;
	}

	// Not yet implemented in the DOM extension (PHP 5.2.6)
	public function rename($new_node_name)
	{
		$this->dom_node->parentNode->renameNode($this->dom_node, $new_node_name);
	}

	public function destroy()
	{
		$this->dom_node->parentNode->removeChild($this->dom_node);
	}

	public function has_child_nodes()
	{
		return $this->dom_node->hasChildNodes();
	}

	/**
	 * Destroy all child nodes and returns this xnode.
	 *
	 * @return xnode
	 */
	public function destroy_child_nodes()
	{
		$child_nodes = $this->dom_node->childNodes;
		
		foreach ($child_nodes as $child_node)
		{
			$this->dom_node->removeChild($child_node);
		}
	}

	/**
	 * @return xdom
	 */
	public function create_xdom_from_node()
	{
		$dom = new DOMDocument("1.0", "UTF-8");
		$dom_node = $dom->importNode($this->dom_node, true);
		$dom->appendChild($dom_node);
		return xdom::create_from_dom($dom);
	}

}

?>